<template>
    <div ref="listRef" class="infinte-list-container" @scroll="scrollHandle">
        <!-- 空白占位 -->
        <div class="empty" :style="{height: itemSize * listData.length + 'px'}"></div>
        <div class="infinte-list" :style="{transform: getTransform}">
            <div 
                class="infinte-list-item" 
                v-for="item in visibleData"
                :key="item.id"
                :style="{height: itemSize + 'px', lineHeight: itemSize + 'px'}"
            >
                {{ item.value }}
            </div>
        </div>
    </div>
</template>

<script setup>
import { reactive, onMounted, computed, ref } from 'vue'
const props = defineProps({
    listData: {
        type: Array,
        default: () => []
    },
    itemSize: {
        type: Number,
        default: 50
    }
})


const state = reactive({
    scrollHeight: 0,
    start: 0,
    end: 0,
    listOffset: 0
})


// 可视区域能展示几条
const visibleCount = computed(() => {
    return Math.ceil(state.scrollHeight / props.itemSize)
})

// 可视区域要展示的数据
const visibleData = computed(() => {
    return props.listData.slice(state.start, Math.min(state.end, props.listData.length))
})

// 列表被带出去后移回
const getTransform = computed(() => {
    return `translateY(${state.listOffset}px)`
})


const listRef = ref(null)
onMounted(() => {
    state.scrollHeight = listRef.value.clientHeight
    state.end = state.start + visibleCount.value
})

const scrollHandle = () => {
    let scrollTop = listRef.value.scrollTop
    // 实时计算 start 和 end
    state.start = Math.floor(scrollTop / props.itemSize)
    state.end = state.start + visibleCount.value
    state.listOffset = scrollTop - (scrollTop % props.itemSize)
}

</script>

<style lang="css" scoped>
.infinte-list-container {
    height: 100%;
    overflow: auto;
    position: relative;
}
.infinte-list {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
}
.infinte-list-item {
    text-align: center;
    border-bottom: 1px solid #eee;
    box-sizing: border-box; 
}
</style>